package com.mop.core.es.dao.dao.impl;

import com.alibaba.fastjson.JSONObject;
import com.lemon.core.common.lang.util.Assert;
import com.lemon.core.common.lang.util.CollectionUtils;
import com.lemon.core.common.lang.util.ObjectUtils;
import com.mop.core.es.dao.config.JestConfig;
import com.mop.core.es.dao.dao.IElasticSearchDao;
import com.mop.core.es.dao.plugins.Pagination;
import com.mop.core.es.dao.plugins.aggs.Statistics;
import com.mop.core.es.dao.plugins.index.Mapping;
import com.mop.core.es.dao.plugins.index.Settings;
import com.mop.core.es.dao.plugins.wraper.QueryWraper;
import com.mop.core.es.dao.util.ESHelper;
import io.searchbox.client.JestClient;
import io.searchbox.client.JestResult;
import io.searchbox.core.*;
import io.searchbox.indices.CreateIndex;
import io.searchbox.indices.DeleteIndex;
import io.searchbox.indices.Flush;
import io.searchbox.indices.IndicesExists;
import io.searchbox.indices.mapping.GetMapping;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;

/**
 * @author lemon
 * @ClassName ElasticSearchDaoImpl
 * @desc
 * @Date 2019/3/8 20:37
 * @Version 1.0
 **/
public class ElasticSearchDaoImpl implements IElasticSearchDao {

    private static JestClient jestClient;

    public ElasticSearchDaoImpl(List<String> serverUris) {
        jestClient = JestConfig.getJestClient(serverUris);
    }

    public static JestClient getJestClient() {
        return jestClient;
    }

    @Override
    public boolean createIndex(String index, String settings, String mapping) {
        boolean result = false;
        Assert.hasLength(mapping, "mapping不可为空!");
        CreateIndex.Builder builder = new CreateIndex.Builder(index.toLowerCase());
        if (StringUtils.isNoneBlank(settings)) {
            builder.settings(settings);
        }
        CreateIndex createIndex = builder.mappings(mapping).build();
        try {
            JestResult jestResult = jestClient.execute(createIndex);
            if (jestResult != null && jestResult.isSucceeded()) {
                result = true;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    @Override
    public <T> boolean createIndex(String index, Settings settings, Mapping mapping) {
        boolean result = false;
        CreateIndex.Builder builder = new CreateIndex.Builder(index.toLowerCase());
        Assert.notNull(mapping, "mappings不可为空!");
        if (!ObjectUtils.isEmpty(settings)) {
            builder.settings(settings.toString());
        }
        CreateIndex createIndex = builder.mappings(mapping.toString()).build();
        JestResult jestResult = null ;
        try {
            jestResult = jestClient.execute(createIndex);
            result = ESHelper.isSucceeded(jestResult);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    @Override
    public boolean deleteIndex(String index) {
        boolean result = false;
        DeleteIndex deleteIndex = new DeleteIndex.Builder(index.toLowerCase()).build();
        JestResult jestResult = null;
        try {
            jestResult = jestClient.execute(deleteIndex);
            result = ESHelper.isSucceeded(jestResult);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    @Override
    public boolean indexExists(String index) {
        boolean result = false;
        IndicesExists indicesExists = new IndicesExists.Builder(index).build();
        JestResult jestResult = null;
        try {
            jestResult = jestClient.execute(indicesExists);
            result = ESHelper.isSucceeded(jestResult);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    @Override
    public boolean flushIndices(String... indices) {
        boolean result = false;
        Flush.Builder builder = new Flush.Builder();
        List<String> indexList = Arrays.asList(indices);
        if (!CollectionUtils.isEmpty(indexList)) {
            builder.addIndices(indexList);
        }
        Flush flush = builder.build();
        JestResult jestResult = null;
        try {
            jestResult = jestClient.execute(flush);
            result = ESHelper.isSucceeded(jestResult);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    @Override
    public String getMapping(String index, String type) {
        String indexMapping = null;
        GetMapping getMapping = new GetMapping.Builder().addIndex(index).addType(type).build();
        JestResult jestResult = null;
        try {
            jestResult = jestClient.execute(getMapping);
            indexMapping = jestResult.getSourceAsObject(JSONObject.class).toString();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return indexMapping;
    }




    @Override
    public <T> boolean insert(T entity) {
        String index = ESHelper.getIndexName(entity.getClass());
        String type = ESHelper.getTypeName(entity.getClass());
        return insert(index, type, entity);
    }


    @Override
    public <T> boolean insert(String index, String type, T entity) {
        boolean result = false;
        Index indexDoc = new Index.Builder(ESHelper.getInsertEntity(entity)).index(index).type(type).id(ESHelper.getDocId(entity)).build();
        JestResult jestResult = null;
        try {
            jestResult = jestClient.execute(indexDoc);
            result = ESHelper.isSucceeded(jestResult);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    @Override
    public <T> boolean bulkInsert(List<T> list) {
        boolean result = false;
        if (CollectionUtils.isEmpty(list)) {
            return result;
        }

        String index = ESHelper.getIndexName(list.get(0).getClass());
        String type = ESHelper.getTypeName(list.get(0).getClass());
        return bulkInsert(index, type, list);
    }

    @Override
    public <T> boolean bulkInsert(String index, String type, List<T> list) {
        boolean result = false;
        Bulk.Builder bulkBuilder = new Bulk.Builder().defaultIndex(index).defaultType(type);
        for (T entity : list) {
            Index indexDoc = new Index.Builder(ESHelper.getInsertEntity(entity)).id(ESHelper.getDocId(entity)).build();
            bulkBuilder.addAction(indexDoc);
        }

        BulkResult bulkResult = null;
        try {
            bulkResult = jestClient.execute(bulkBuilder.build());
            result = ESHelper.isSucceeded(bulkResult);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    @Override
    public <T> boolean update(T entity) {
        String index = ESHelper.getIndexName(entity.getClass());
        String type = ESHelper.getTypeName(entity.getClass());
        return update(index, type, entity);
    }

    @Override
    public <T> boolean update(String index, String type, T entity) {
        boolean result = false;
        T oldEntity = selectById(entity);
        if (ObjectUtils.isEmpty(oldEntity)) {
            return false;
        }
        Index indexDoc = new Index.Builder(ESHelper.getUpdateEntity(oldEntity, entity)).index(index).type(type).id(ESHelper.getDocId(entity)).build();
        DocumentResult documentResult = null;
        try {
            documentResult = jestClient.execute(indexDoc);
            result = ESHelper.isSucceeded(documentResult);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    @Override
    public <T> boolean bulkUpdate(List<T> list) {
        if (list.size() == 0) {
            return false;
        }
        String index = ESHelper.getIndexName(list.get(0).getClass());
        String type = ESHelper.getTypeName(list.get(0).getClass());
        return bulkUpdate(index, type, list);
    }

    @Override
    public <T> boolean bulkUpdate(String index, String type, List<T> list) {
        boolean result = false;
        if (CollectionUtils.isEmpty(list)) {
            return result;
        }
        Bulk.Builder bulkBuilder = new Bulk.Builder().defaultIndex(index).defaultType(type);;
        for (T entity : list) {
            T oldEntity = selectById(entity);
            Index indexDoc = new Index.Builder(ESHelper.getUpdateEntity(oldEntity, entity)).id(ESHelper.getDocId(entity)).build();
            bulkBuilder.addAction(indexDoc);
        }

        BulkResult bulkResult = null;
        try {
            bulkResult = jestClient.execute(bulkBuilder.build());
            result = ESHelper.isSucceeded(bulkResult);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    @Override
    public <T> boolean insertOrUpdate(T entity) {
        T oldEntity = selectById(entity);
        if (ObjectUtils.isEmpty(oldEntity)) {
            return insert(entity);
        }
        return update(entity);
    }

    @Override
    public <T> boolean delete(T entity) {
        String index = ESHelper.getIndexName(entity.getClass());
        String type = ESHelper.getTypeName(entity.getClass());
        String docId = ESHelper.getDocId(entity);
        return delete(index, type, docId);
    }

    @Override
    public boolean delete(String index, String type, String id) {
        boolean result = false;
        Delete delete = new Delete.Builder(id).index(index).type(type).build();
        DocumentResult documentResult = null;
        try {
            documentResult = jestClient.execute(delete);
            result = ESHelper.isSucceeded(documentResult);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    @Override
    public <T> boolean bulkDelete(List<T> list) {
        boolean result = false;
        if (CollectionUtils.isEmpty(list)) {
            return result;
        }

        String index = ESHelper.getIndexName(list.get(0).getClass());
        String type = ESHelper.getTypeName(list.get(0).getClass());
        return bulkDelete(index, type, list);
    }

    @Override
    public <T> boolean bulkDelete(String index, String type, List<T> list) {
        boolean result = false;
        Bulk.Builder bulkBuilder = new Bulk.Builder();
        for (T entity : list) {
            Delete delete = new Delete.Builder(ESHelper.getDocId(entity)).index(index).type(type).build();
            bulkBuilder.addAction(delete);
        }

        BulkResult bulkResult = null;
        try {
            bulkResult = jestClient.execute(bulkBuilder.build());
            result = ESHelper.isSucceeded(bulkResult);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }



    @Override
    public <T> T selectById(T entity) {
        String index = ESHelper.getIndexName(entity.getClass());
        String type = ESHelper.getTypeName(entity.getClass());
        return selectById(index, type, entity);
    }

    @Override
    public <T> T selectById(String index, String type, T entity) {
        QueryWraper<T> queryWraper = new QueryWraper<T>();
        queryWraper.match("_id", ESHelper.getDocId(entity));
        try {
            T newInstance = (T) entity.getClass().newInstance();
            queryWraper.setEntity(newInstance);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        List<T> list = selectList(index, type, queryWraper);
        return list.size() > 0 ? list.get(0) : null;
    }

    @Override
    public <T> List<T> selectList(QueryWraper<T> queryWraper) {
        String index = ESHelper.getIndexName(queryWraper);
        String type = ESHelper.getTypeName(queryWraper);
        return selectList(index, type, queryWraper);
    }

    @Override
    public <T> List<T> selectList(String index, String type, QueryWraper<T> queryWraper) {
        return ESHelper.selectRecords(index, type, queryWraper);
    }


    @Override
    public <T> List<T> selectPage(Pagination pagination) {
        String index = ESHelper.getIndexName(pagination.getQueryWraper());
        String type = ESHelper.getTypeName(pagination.getQueryWraper());
        return selectPage(index, type, pagination);
    }

    @Override
    public <T> List<T> selectPage(String index, String type, Pagination pagination) {
        Integer current = pagination.getCurrent() == null ? 1 : pagination.getCurrent();
        Integer size = pagination.getSize() == null ? 10 : pagination.getSize();
        Integer start = (current - 1) * size + 1;
        Integer end = current * size;
        return ESHelper.selectRecords(index, type, pagination.getQueryWraper());
    }


    @Override
    public <T> List<Statistics> selectAggs(QueryWraper<T> queryWraper) {
        return ESHelper.selectAggs(queryWraper);
    }
}
